/**
 *
 */
package com.cmcc.pcap.jpcap.capture;

import java.util.Date;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import jpcap.PacketReceiver;
import jpcap.packet.EthernetPacket;
import jpcap.packet.IPPacket;
import jpcap.packet.Packet;
import jpcap.packet.TCPPacket;
import jpcap.packet.UDPPacket;
import com.cmcc.pcap.jpcap.jpcap.packet.VLanIPPacket;
import com.cmcc.pcap.jpcap.tcp.TcpDispatcher;
import com.cmcc.pcap.jpcap.udp.UdpDispatcher;
import com.cmcc.pcap.jpcap.util.CommonUtils;

public class PacketHandler implements  PacketReceiver ,HandlerControl{
	private static Logger logger = LogManager.getLogger(PacketHandler.class);
	TcpDispatcher tcpDispatcher ;
	UdpDispatcher udpDispatcher ;
	JCaptures jCaptures;
	public PacketHandler(JCaptures jCaptures,String taskId){
		this.jCaptures = jCaptures;
		
		//根据filter配置启动不同的xxxDispatcher
		if("udp".equalsIgnoreCase(this.jCaptures.filter)){
			this.udpDispatcher = new UdpDispatcher(jCaptures,taskId);
		}else if("tcp".equalsIgnoreCase(this.jCaptures.filter)){
			this.tcpDispatcher = new TcpDispatcher(jCaptures,taskId);
		}else{
			this.tcpDispatcher = new TcpDispatcher(jCaptures,taskId);
			this.udpDispatcher = new UdpDispatcher(jCaptures,taskId);
		}
		
	}
	
	//允许用户设置自定义TcpDispatcher？？？
//	public void setTcpDispatcher(TcpDispatcher tcpDispatcher){
//		this.tcpDispatcher = tcpDispatcher;
//	}
	
	
	/**
	 * 
	 * packet.header.length = tcpPacket.header.length:TCP最常见值是 54(14+20+20),DUP最常见42(14+20+8)
	 * packet.data.length = tcpPacket.data.length:
	 * 
	 */
	@Override
	public void receivePacket(Packet packet) {
		try{
			logger.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
			EthernetPacket ethP = (EthernetPacket)packet.datalink;
			logger.debug(ethP.toString());
	
			logger.debug("packet.header.length : "+packet.header.length);
			logger.debug("packet.data.length : "+packet.data.length);
			
			logger.debug("packet.time : "+new Date(packet.sec*1000));
			logger.debug("packet.microsecond : "+packet.usec);
	   	    
	   	    /**
	   	     * ETHERTYPE_PUP = 512;
			   ETHERTYPE_IP = 2048;
			   ETHERTYPE_ARP = 2054;
			   ETHERTYPE_REVARP = -32715;
			   ETHERTYPE_VLAN = -32512;
			   ETHERTYPE_IPV6 = -31011;
			   ETHERTYPE_LOOPBACK = -28672;
	   	     */
	   	    switch(ethP.frametype){
	   	    case 2048:
	   	    case -31011:
	   	    	logger.debug("ip packet");
	   	    	IPPacket ipPacket = (IPPacket) packet;
	   	    	this.dealIPPacket(ipPacket);
	   	        break;
	   	    case 2054:
	   	    	logger.debug("arp packet do nothing");
		        break;
	   	    case -32512:
	   	    	logger.debug("vlan packet");
                //TODO 自己实现对Packet的解析生成去掉VLAN头的IPPacket？
	   	    	IPPacket ReCodeIpPacket = VLanIPPacket.reCodeIpPacket(packet);
	   	    	if(ReCodeIpPacket != null)
	   	    	    this.dealIPPacket(ReCodeIpPacket);
		        break;
	   	    default:
	   	    	logger.error("do not support enthernet type :"+ethP.frametype);
	   	    	break;
	   	    }
		}catch(Exception e){
	    		logger.error(e.getCause(),e);
	    }
	}
	
	public void dealIPPacket(IPPacket ipPacket){
		
		
		String src_ip;
    	int src_port;
    	String dst_ip;
    	int dst_port;
    	short protocol;
		
		/**
		 * IPPROTO_ICMP = 1;
		   IPPROTO_IGMP = 2;
		   IPPROTO_IP = 4;
		   IPPROTO_TCP = 6;  will support
		   IPPROTO_UDP = 17;  support
		   IPPROTO_IPv6 = 41;
		   IPPROTO_HOPOPT = 0;
		   IPPROTO_IPv6_Route = 43;
		   IPPROTO_IPv6_Frag = 44;
		   IPPROTO_IPv6_ICMP = 58;
		   IPPROTO_IPv6_NoNxt = 59;
		   IPPROTO_IPv6_Opts = 60; 
		 */
		switch(ipPacket.protocol){
		case 17:
			/**  
			 * MF=0,OFFSET=0  不是分片
			   MF=1,OFFSET=0 第一个分片
			   MF=1,OFFSET=X 中间某个分片
			   MF=0,OFFSET=X 最后一个分片
			 */
			if(ipPacket.more_frag || ipPacket.offset> 0){
				logger.error("the ip packet is a fragment ");
				/**
				 * TODO
				 * 此处应该先处理IP分片的重组，否则可能导致强制类型转换成UDPPacket时报 java.lang.ClassCastException错
				 * 因为IP多个分片只有第一个分片会携带UDP Header（注意TCP不会产生IP分片） 
				 */
			}
			
			
			logger.debug("UDP packet");
	    	UDPPacket udpPacket = (UDPPacket)ipPacket;
	        	 
	    	 /**
	    	  * 五元组(源IP、源端口、目的IP、目的端口、协议。代码到这里已经确定传输层协议是UDP，应用层协议需要另行分析)
	    	  * TODO 需要一个用于分析应用层协议是何种协议的独立类或方法
	    	  */
	    	src_ip = udpPacket.src_ip.getHostAddress();
	    	src_port = udpPacket.src_port;
	    	dst_ip = udpPacket.dst_ip.getHostAddress();
	    	dst_port = udpPacket.dst_port;
	    	protocol = udpPacket.protocol;
	    	logger.debug("udp quintet :<"+src_ip+","+src_port+","+dst_ip+","+dst_port+","+protocol+">");
	    	//logger.debug(udpPacket.toString());
	    	//logger.debug(udpPacket.data); //TODO 处理应用层协议
	    	this.udpDispatcher.dispatcherUdpPacket(udpPacket);
			break;
        case 6:
        	logger.debug("TCP packet");
	    	
	    	TCPPacket tcpPacket = (TCPPacket)ipPacket;
	    	 
	    	/**
	          * 五元组(源IP、源端口、目的IP、目的端口、协议。代码到这里已经确定传输层协议是TCP，应用层协议需要另行分析)
	    	  * TODO 需要一个用于分析应用层协议是何种协议的独立类或方法
	    	  */
	    	src_ip = tcpPacket.src_ip.getHostAddress();
	    	src_port = tcpPacket.src_port;
	    	dst_ip = tcpPacket.dst_ip.getHostAddress();
	    	dst_port = tcpPacket.dst_port;
	    	protocol = tcpPacket.protocol;
	    	logger.debug("tcp quintet :<"+src_ip+","+src_port+","+dst_ip+","+dst_port+","+protocol+">");
	    	
	    	tcpDispatcher.dispatcherTcpPacket(tcpPacket);
	    	
			break;
		default:
			logger.error("do not support ip protocol :"+ipPacket.protocol);
			logger.error("the data is  :"+ CommonUtils.bytesToHexString(ipPacket.data));
			break;
		
		}
	}

	/**
	 * 如果有多个其他dispatcher也要依次stop
	 */
	@Override
	public void stop() {
		logger.info("[ stoping PacketHandler ]");
		//logger.info("stop TcpDispatcher");
		if(this.tcpDispatcher != null)
		    this.tcpDispatcher.stop();
		
		if(this.udpDispatcher != null)
		    this.udpDispatcher.stop();
		
		logger.info("[ stoped PacketHandler ]");
	}
	
	

}
